<template>
  <div class="tree">
    <div class="search-input">
      <el-input
        v-model="filterText"
        :placeholder="placeholder"
        :suffix-icon="Search"
        clearable
      />
    </div>
    <el-scrollbar class="tree_body" height="calc(100% - 42px)">
      <el-tree
        ref="treeRef_ui"
        v-loading="loading"
        :data="treeData"
        :node-key="propsMap.value"
        :props="propsMap"
        :empty-text="emptyText"
        :show-checkbox="showCheckBox"
        :check-strictly="checkStrictly"
        :default-checked-keys="defaultCheckedKeys"
        :current-node-key="currentNodeKey || customCurrentNodeKey"
        :default-expand-all="defaultExpandAll"
        :default-expanded-keys="defaultExpandedKeys"
        :auto-expand-parent="autoExpandParent"
        :expand-on-click-node="expandOnClickNode"
        :highlight-current="highlightCurrent"
        :render-after-expand="renderAfterExpand"
        :draggable="draggable"
        :icon="icon"
        :accordion="accordion"
        @check="check"
        @node-click="(data, node, _, e) => nodeClickCustom(data, node, _, e)"
        @node-contextmenu="nodeContextMenu"
        @check-change="checkChange"
        @current-change="currentChange"
        @node-expand="nodeExpand"
        @node-collapse="nodeCollapse"
        @node-drag-start="nodeDragStart"
        @node-drag-enter="nodeDragEnter"
        @node-drag-leave="nodeDragLeave"
        @node-drag-over="nodeDragOver"
        @node-drag-end="nodDragEnd"
        @node-drop="nodeDrop"
      >
        <template #default="{ node }">
          <span class="custom-tree-node">
            <span
              :class="propsMap.class || 'tree-span'"
              :title="node.data[propsMap.label]"
              >{{ node.data[propsMap.label] }}</span
            >
            <el-popover
              v-if="needOperate"
              ref="popover_gudch_ui"
              trigger="hover"
              :show-arrow="false"
              placement="right-start"
            >
              <template #reference>
                <span
                  class="edit-span"
                  v-show="editIconClickMap[node.data[props.propsMap.value]]"
                >
                  <el-icon class="tree-icon"
                    ><MoreFilled class="tree-icon-body"
                  /></el-icon>
                </span>
              </template>
              <ul class="tree-ul">
                <li
                  class="tree-ul-li"
                  key="1"
                  v-if="operateMap.includes(1)"
                  @click="() => showDialog(node, 1)"
                >
                  新建同级
                </li>
                <li
                  class="tree-ul-li"
                  key="2"
                  v-if="operateMap.includes(2)"
                  @click="() => showDialog(node, 2)"
                >
                  新建子级
                </li>
                <li
                  class="tree-ul-li"
                  key="3"
                  v-if="operateMap.includes(3)"
                  @click="() => showDialog(node, 3)"
                >
                  修改
                </li>
                <li
                  class="tree-ul-li"
                  key="4"
                  v-if="operateMap.includes(4)"
                  @click="() => deleteTreeData(node)"
                >
                  删除
                </li>
              </ul>
            </el-popover>
          </span>
        </template>
      </el-tree>
      <el-dialog
        v-model="dialogFormVisible"
        :title="dialogTitle"
        draggable
        :align-center="true"
        @close="() => closeDialog()"
        width="450px"
      >
        <el-form
          ref="treeForm_gudch_ui"
          label-position="top"
          :model="form"
          :rules="rules"
          style="width: 90%; margin: auto"
        >
          <el-form-item
            label="节点名称"
            label-width="100px"
            placeholder="请输入节点名称"
            :prop="props.propsMap.label"
          >
            <el-input v-model="form[props.propsMap.label]" />
          </el-form-item>
          <el-form-item
            label="节点id"
            label-width="100px"
            style="display: none"
            :prop="props.propsMap.value"
          >
            <el-input v-model="form[props.propsMap.value]" />
          </el-form-item>
          <el-form-item
            label="父节点id"
            label-width="100px"
            style="display: none"
            :prop="props.propsMap.parentId"
          >
            <el-input v-model="form[props.propsMap.parentId]" />
          </el-form-item>
        </el-form>
        <template #footer>
          <span class="dialog-footer">
            <el-button @click="() => dialogCancel()">取消</el-button>
            <el-button type="primary" @click="() => submitForm()">
              完成
            </el-button>
          </span>
        </template>
      </el-dialog>
    </el-scrollbar>
  </div>
</template>

<script setup>
import { ref, watch, reactive, getCurrentInstance, toRefs } from "vue";
import { onMounted } from "@vue/runtime-core";
import { ElMessage, IconComponentMap, ElMessageBox } from "element-plus";
import { MoreFilled, Search } from "@element-plus/icons-vue";
const loading = ref(false);
// 当前document对象
const proxy = getCurrentInstance();
// 刚才被操作的树节点data对象
const editObject = ref({});
// 树组件对象
const treeData = ref([]);
// 缓存当前树组件对象
const treeDataTemp = ref([]);
// 弹出框的title
const dialogTitle = ref("");
// 搜索框内容
const filterText = ref("");
// 当前点击的icon
const editIconClickMap = ref({});
// 弹出框是否显示
const dialogFormVisible = ref(false);
const customCurrentNodeKey = ref(undefined);
// 对外暴露的参数
const props = defineProps({
  // 删除后回调
  onDelete: {
    type: Function,
    default: () => {},
  },
  // 搜索后回调
  afterSearch: {
    type: Function,
    default: () => {},
  },
  // 点击完成后触发的事件
  onSave: {
    type: Function,
    default: () => {},
  },
  // dialog关闭后触发的事件
  afterClose: {
    type: Function,
    default: () => {},
  },
  // 点击取消后触发的事件
  afterCancel: {
    type: Function,
    default: () => {},
  },
  nodeClick: {
    type: Function,
    default: (data) => {},
  },
  nodeContextMenu: {
    type: Function,
    default: () => {},
  },
  checkChange: {
    type: Function,
    default: () => {},
  },
  currentChange: {
    type: Function,
    default: () => {},
  },
  nodeExpand: {
    type: Function,
    default: () => {},
  },
  nodeCollapse: {
    type: Function,
    default: () => {},
  },
  nodeDragStart: {
    type: Function,
    default: () => {},
  },
  nodeDragEnter: {
    type: Function,
    default: () => {},
  },
  nodeDragLeave: {
    type: Function,
    default: () => {},
  },
  nodeDragOver: {
    type: Function,
    default: () => {},
  },
  nodDragEnd: {
    type: Function,
    default: () => {},
  },
  nodeDrop: {
    type: Function,
    default: () => {},
  },
  check: {
    type: Function,
    default: () => {},
  },
  showCheckBox: { type: Boolean, default: false },
  checkStrictly: { type: Boolean, default: false },
  defaultCheckedKeys: {
    type: Array,
    default: () => [],
  },
  currentNodeKey: {
    type: String,
    default: "",
  },
  emptyText: { type: String, default: "暂无数据" },
  defaultExpandAll: { type: Boolean, default: false },
  defaultExpandedKeys: {
    type: Array,
    default: () => ["-1"],
  },
  autoExpandParent: { type: Boolean, default: true },
  expandOnClickNode: { type: Boolean, default: false },
  highlightCurrent: { type: Boolean, default: true },
  renderAfterExpand: { type: Boolean, default: true },
  // 是否开启拖拽节点功能
  draggable: { type: Boolean, default: false },
  // 自定义树节点图标组件 string | Component
  icon: {
    type: Object,
    default: () => {},
  },
  // 是否每次只打开一个同级树节点展开
  accordion: { type: Boolean, default: false },
  // 最大层级
  maxlevel: { type: Number, default: 7 },
  // 需要操作图标
  needOperate: { type: Boolean, default: true },
  // 组件原始数据
  dataSource: {
    type: Object,
    default: () => [],
  },
  // 可选的操作项，增（1、同级，2、子级），3、删，4、改
  operateMap: {
    type: Array,
    default: () => [1, 2, 3, 4],
  },
  // 属性定义
  propsMap: {
    type: Object,
    default: () => {
      return {
        value: "id", // ID字段名
        parentId: "parentId", // ID字段名
        label: "label", // 显示名称
        children: "children", // 子节点
        disabled: "disabled", // 当前节点是否可用
        class: "class", // 当前节点的
      };
    },
  },
  // 搜索框提示
  placeholder: {
    type: String,
    default: () => "搜索",
  },
});
// 节点增删改使用的表单数据
const formData = reactive({
  form: {
    [props.propsMap.label]: undefined,
    [props.propsMap.value]: undefined,
    [props.propsMap.parentId]: undefined,
  },
  rules: {
    [props.propsMap.label]: [
      { required: true, message: "节点名称不能为空", trigger: "change" },
      {
        validator: checkName,
        trigger: "blur",
      },
    ],
  },
});

// 需要对外暴露的api
defineExpose({
  init,
  initUUID,
  getNode,
  getCurrentKey,
  getCheckedKeys,
  getCurrentTree,
  getCurrentNode,
  getCheckedNodes,
  getLastEditObject,
  getHalfCheckedKeys,
  getHalfCheckedNodes,
  getCurrentTreeTrueData,
  setChecked,
  setCurrentKey,
  setCheckedKeys,
  setCurrentNode,
  setCheckedNodes,
  updateKeyChildren,
  updateKeyChildren_package,
  remove,
  insertAfter,
  append,
  insertBefore,
});

// 获取当前显示的树结构
function getCurrentTree() {
  return treeData.value;
}
// 获取刚才操作过的节点data对象
function getLastEditObject() {
  return editObject.value;
}
// 获取当前真实的树结构
function getCurrentTreeTrueData() {
  return treeDataTemp.value;
}
// 更新某个节点 原生
function updateKeyChildren(key, data) {
  proxy.refs["treeRef_ui"].updateKeyChildren(key, data);
}
// 更新某个节点，封装
function updateKeyChildren_package(data) {
  return updateDataByValue(treeData.value, data);
}
// 如果节点可以被选中，(show-checkbox 为 true), 本方法将返回当前选中节点的数组
function getCheckedNodes(leafOnly, includeHalfChecked) {
  return proxy.refs["treeRef_ui"].getCheckedNodes(leafOnly, includeHalfChecked);
}
// 设置目前勾选的节点，使用此方法必须提前设置 node-key 属性
function setCheckedNodes(array) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      resolve(proxy.refs["treeRef_ui"].setCheckedNodes(array));
    }, 300);
  });
}
// 若节点可以被选中 (show-checkbox 为 true), 它将返回当前选中节点 key 的数组
function getCheckedKeys(leafOnly) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      resolve(proxy.refs["treeRef_ui"].getCheckedKeys(leafOnly));
    }, 300);
  });
}
// 设置目前选中的节点，使用此方法必须设置 node-key 属性
function setCheckedKeys(keys, leafOnly) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      resolve(proxy.refs["treeRef_ui"].setCheckedKeys(keys, leafOnly));
    }, 300);
  });
}
// 设置节点是否被选中, 使用此方法必须设置 node-key 属性
function setChecked(data, checked, deep) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      resolve(proxy.refs["treeRef_ui"].setChecked(data, checked, deep));
    }, 300);
  });
}
// 如果节点可以被选中 (show-checkbox 为 true), 它将返回当前半选中的节点组成的数组
function getHalfCheckedNodes() {
  return proxy.refs["treeRef_ui"].getHalfCheckedNodes();
}
// 若节点可被选中(show-checkbox 为 true)，则返回目前半选中的节点的 key 所组成的数组
function getHalfCheckedKeys() {
  return proxy.refs["treeRef_ui"].getHalfCheckedKeys();
}
// 返回当前被选中节点的数据 (如果没有则返回 null)
function getCurrentKey() {
  return proxy.refs["treeRef_ui"].getCurrentKey();
}
// 返回当前被选中节点的数据 (如果没有则返回 null)
function getCurrentNode() {
  return proxy.refs["treeRef_ui"].getCurrentNode();
}
// 通过 key 设置某个节点的当前选中状态，使用此方法必须设置 node-key  属性
function setCurrentKey(key, shouldAutoExpandParent) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      resolve(
        proxy.refs["treeRef_ui"].setCurrentKey(key, shouldAutoExpandParent)
      );
    }, 300);
  });
}
// 设置节点为选中状态，使用此方法必须设置 node-key 属性
function setCurrentNode(node, shouldAutoExpandParent) {
  return new Promise(function (resolve, reject) {
    setTimeout(() => {
      resolve(
        proxy.refs["treeRef_ui"].setCurrentNode(node, shouldAutoExpandParent)
      );
    }, 300);
  });
}
// 根据 data 或者 key 拿到 Tree 组件中的 node
function getNode(data) {
  return proxy.refs["treeRef_ui"].getNode(data);
}
// 删除 Tree 中的一个节点，使用此方法必须设置 node-key 属性
function remove(data) {
  return proxy.refs["treeRef_ui"].remove(data);
}
// 为 Tree 中的一个节点追加一个子节点
function append(data, parentNode) {
  return proxy.refs["treeRef_ui"].append(data, parentNode);
}
// 在 Tree 中给定节点前插入一个节点
function insertBefore(data, refNode) {
  return proxy.refs["treeRef_ui"].insertBefore(data, refNode);
}
// 在 Tree 中给定节点后插入一个节点
function insertAfter(data, refNode) {
  return proxy.refs["treeRef_ui"].insertAfter(data, refNode);
}
/** 自定义表单校验，校验节点名称是否重复或不为空 */
function checkName(rule, label, callback) {
  if (!label || label.trim() == "") {
    form.value[props.propsMap.label] = "";
    callback(new Error("节点名称不能为空"));
  } else {
    const specialCharForUri_pattern =
      /[【*^+&@#%=~|$?!:,.{}()<>"\';！￥…（）—】]/g;
    if (specialCharForUri_pattern.test(label)) {
      callback("不允许输入特殊字符：【*^+&@#%=~|$?!:,.{}()<>\"';！￥…（）—】");
    } else {
      const value = form.value[props.propsMap.value];
      const treeData = findTreeData(treeDataTemp.value, label);
      if (
        JSON.stringify(treeData) != "{}" &&
        treeData[props.propsMap.value] != value
      ) {
        callback(new Error("节点名称不能重复"));
      } else {
        callback();
      }
    }
  }
}

const { form, rules } = toRefs(formData);
let timer = null;
// 监听搜索框变化
watch(filterText, (val) => {
  // 防抖操作
  if (timer != null) {
    clearTimeout(timer);
  }
  timer = setTimeout(() => {
    if (val) treeData.value = filterDataTree(treeDataTemp.value, val);
    else treeData.value = treeDataTemp.value;
    if (editIconClickMap.value) {
      // 清空已选的节点
      Object.keys(editIconClickMap.value).forEach((key) => {
        editIconClickMap.value[key] = false;
      });
    }
    props.afterSearch(treeData.value);
  }, 300);
});

/**
 *  搜索
 * @param {*} tree
 * @param {*} val
 */
function filterDataTree(tree, val) {
  let newTree = [];
  tree.forEach((item) => {
    if (item[props.propsMap.label].indexOf(val) != -1) {
      newTree.push(item);
    } else if (
      item[props.propsMap.children] &&
      item[props.propsMap.children].length > 0
    ) {
      newTree = newTree.concat(
        filterDataTree(item[props.propsMap.children], val)
      );
    }
  });
  return newTree;
}

/**
 * 查找单个的节点
 * @param {*} tree
 * @param {*} val
 */
function findTreeData(tree, val) {
  let newTree = {};
  tree.forEach((item) => {
    if (item[props.propsMap.label] == val) {
      newTree = item;
    } else if (
      item[props.propsMap.children] &&
      item[props.propsMap.children].length > 0
    ) {
      newTree = findTreeData(item[props.propsMap.children], val);
    }
  });
  return newTree;
}

/**
 * 节点删除前判断
 * @param {*} param
 */
function deleteTreeData(param) {
  ElMessageBox.confirm("确认要删除当前节点吗？", "系统提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
  })
    .then(() => {
      let node = null;
      if (param?.data) node = proxy.refs["treeRef_ui"].getNode(param.data);
      else node = proxy.refs["treeRef_ui"].getNode(param);
      if (node) {
        if (
          node.data[props.propsMap.children] &&
          node.data[props.propsMap.children].length > 0
        ) {
          ElMessage.error("存在下级节点，无法删除！");
        } else {
          props.onDelete(param, () => delCallback(node));
        }
      } else {
        ElMessage.error("删除失败！", node);
      }
    })
    .catch(() => {});
}

const delCallback = (node) => {
  if (proxy.refs["treeRef_ui"]) {
    proxy.refs["treeRef_ui"].remove(node);
    treeDataTemp.value = treeData.value;
    editObject.value = node.data;
    ElMessage.success("删除成功！");
  }
};
/**
 * 删除树的某个节点
 * @param {*} tree
 * @param {*} child
 * @param {*} parent
 */
function deleteDataByValue(tree, child, parent) {
  let newTree = [];
  tree.forEach((item) => {
    let newItem = { ...item };
    if (item[props.propsMap.value] != child[props.propsMap.value]) {
      if (!parent) {
        newTree.push(newItem);
      } else {
        parent[props.propsMap.children].push(newItem);
      }
    }
    if (
      item[props.propsMap.children] &&
      item[props.propsMap.children].length > 0
    ) {
      newItem[props.propsMap.children] = [];
      deleteDataByValue(item[props.propsMap.children], child, newItem);
    }
  });
  return newTree;
}

/**
 * 重置表单
 */
function dialogCancel() {
  proxy.refs["treeForm_gudch_ui"].resetFields();
  dialogFormVisible.value = false;
  // 取消时回调
  props.afterCancel();
}

/**
 * 重置表单
 */
function closeDialog() {
  proxy.refs["treeForm_gudch_ui"].resetFields();
  dialogFormVisible.value = false;
  // 取消时回调
  props.afterClose();
}

/**
 * 提交表单
 */
function submitForm() {
  proxy.refs["treeForm_gudch_ui"].validate((valid) => {
    if (valid) {
      props.onSave(form.value, () => submitCallback());
    }
  });
}

function submitCallback() {
  dialogFormVisible.value = false;
  let newTree = { ...form.value };
  let oldTree = updateDataByValue(treeData.value, newTree);
  if (JSON.stringify(oldTree) == "{}") {
    // insertDataByParentId(treeData.value, newTree);
    proxy.refs["treeRef_ui"].append(newTree, newTree[props.propsMap.parentId]);
  }
  treeDataTemp.value = treeData.value;
  editObject.value = newTree;
}

/**
 * 给某个父节点增加子节点
 * @param {*} tree
 * @param {*} child
 */
function insertDataByParentId(tree, child) {
  let newTree = {};
  tree.forEach((item) => {
    if (item[props.propsMap.value] == child[props.propsMap.parentId]) {
      newTree = item;
      if (!item[props.propsMap.children]) {
        item[props.propsMap.children] = [];
      }
      item[props.propsMap.children].push(child);
    } else if (
      item[props.propsMap.children] &&
      item[props.propsMap.children].length > 0 &&
      JSON.stringify(newTree) == "{}"
    ) {
      newTree = insertDataByParentId(item[props.propsMap.children], child);
    }
  });
  return newTree;
}

/**
 * 初始化editIconClickMap
 */
function initEditIconClickMap(treeData) {
  if (treeData?.value) {
    treeData.value.forEach((item) => {
      editIconClickMap.value[item[props.propsMap.value]] = false;
      if (
        item[props.propsMap.children] &&
        item[props.propsMap.children].length > 0
      ) {
        initEditIconClickMap(item[props.propsMap.children]);
      }
    });
  }
}

/**
 * 根据节点id更新节点
 * @param {*} tree
 * @param {*} child
 */
function updateDataByValue(tree, child) {
  let newTree = {};
  if (child[props.propsMap.parentId] == "-1") {
    tree.forEach((item) => {
      if (item[props.propsMap.value] == child[props.propsMap.value]) {
        newTree = item;
        item[props.propsMap.label] = child[props.propsMap.label];
      }
    });
    if (JSON.stringify(newTree) == "{}") tree.push(child);
    newTree = { ...child };
  } else {
    tree.forEach((item) => {
      if (item[props.propsMap.value] == child[props.propsMap.value]) {
        newTree = item;
        item[props.propsMap.label] = child[props.propsMap.label];
      } else if (
        item[props.propsMap.children] &&
        item[props.propsMap.children].length > 0 &&
        JSON.stringify(newTree) == "{}"
      ) {
        newTree = updateDataByValue(item[props.propsMap.children], child);
      }
    });
  }
  return newTree;
}

/**
 * 打开dialog，并根据操作类型初始化表单
 * @param {*} node
 * @param {*} type
 */
function showDialog(node, type) {
  switch (type) {
    case 1:
      if (node.level >= props.maxlevel) {
        ElMessage.error(`节点层级最多${props.maxlevel}级`);
      } else {
        form.value[props.propsMap.parentId] =
          node.data[props.propsMap.parentId];
        form.value[props.propsMap.value] = initUUID();
        dialogTitle.value = "新增同级节点";
        dialogFormVisible.value = true;
      }
      break;
    case 2:
      if (node.level >= props.maxlevel) {
        ElMessage.error(`节点层级最多${props.maxlevel}级`);
      } else {
        form.value[props.propsMap.parentId] = node.data[props.propsMap.value];
        form.value[props.propsMap.value] = initUUID();
        dialogTitle.value = "新增下级节点";
        dialogFormVisible.value = true;
      }
      break;
    case 3:
      form.value[props.propsMap.label] = node.data[props.propsMap.label];
      form.value[props.propsMap.value] = node.data[props.propsMap.value];
      form.value[props.propsMap.parentId] = node.data[props.propsMap.parentId];
      dialogTitle.value = "修改当前节点";
      dialogFormVisible.value = true;
      break;
    default:
      break;
  }
}

/**
 * 生成uuid
 */
function initUUID() {
  let uuid = "";
  const list = generateUUID().split("-");
  list.forEach((item) => {
    uuid += item;
  });
  return uuid;
}

/**
 * uuid初始值
 */
const generateUUID = () => {
  var d = new Date().getTime();
  if (window.performance && typeof window.performance.now === "function") {
    d += performance.now(); //use high-precision timer if available
  }
  var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
    /[xy]/g,
    function (c) {
      var r = (d + Math.random() * 16) % 16 | 0;
      d = Math.floor(d / 16);
      return (c == "x" ? r : (r & 0x3) | 0x8).toString(16);
    }
  );
  return uuid;
};

/**
 * 点树组件后面操作icon时，设置icon的显隐状态
 * @param {*} e
 * @param {*} node
 */
function editSpanClick(e, node) {
  if (e) {
    e.stopPropagation();
  }
  if (editIconClickMap.value) {
    Object.keys(editIconClickMap.value).forEach((key) => {
      editIconClickMap.value[key] = false;
    });
    editIconClickMap.value[node.data[props.propsMap.value]] = true;
  }
  // props.nodeClick();
}

/**
 * 加载初始化数据
 */
onMounted(() => {
  init();
});
/**
 * 页面初始化
 */
function init() {
  loading.value = true;
  treeData.value = props.dataSource;
  treeDataTemp.value = props.dataSource;
  initEditIconClickMap(treeDataTemp.value);
  if (!customCurrentNodeKey.value) {
    customCurrentNodeKey.value = props.currentNodeKey;
  }
  editIconClickMap.value[customCurrentNodeKey.value] = true;
}

watch([props], (val, v) => {
  if (filterText.value == "") {
    init();
  }
  loading.value = false;
  proxy.emit(
    "update:currentNodeKey",
    customCurrentNodeKey.value || props.currentNodeKey
  );
});

function nodeClickCustom(data, node, _, e) {
  if (e) {
    e.stopPropagation();
  }
  if (editIconClickMap.value) {
    Object.keys(editIconClickMap.value).forEach((key) => {
      editIconClickMap.value[key] = false;
    });
    editIconClickMap.value[node.data[props.propsMap.value]] = true;
  }
  customCurrentNodeKey.value = data[props.propsMap.value];
  proxy.emit(
    "update:currentNodeKey",
    customCurrentNodeKey.value || props.currentNodeKey
  );
  if (props.nodeClick) {
    props.nodeClick(data);
  }
}
</script>

<style lang="scss" scoped>
@import "./index.css";
:deep(.ep-form-item__label) {
  margin-bottom: 8px;
  line-height: 22px;
  margin-top: 12px !important;
}
</style>